package org.dslintegration.serializer;

import com.google.inject.Inject;
import com.google.inject.Provider;
import org.dslintegration.kM3.Attribute;
import org.dslintegration.kM3.Datatype;
import org.dslintegration.kM3.Enumeration;
import org.dslintegration.kM3.KM3Class;
import org.dslintegration.kM3.KM3Package;
import org.dslintegration.kM3.Literal;
import org.dslintegration.kM3.Metamodel;
import org.dslintegration.kM3.Multiplicity;
import org.dslintegration.kM3.Reference;
import org.dslintegration.kM3.TypeRef;
import org.dslintegration.services.KM3GrammarAccess;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.serializer.acceptor.ISemanticSequenceAcceptor;
import org.eclipse.xtext.serializer.acceptor.SequenceFeeder;
import org.eclipse.xtext.serializer.diagnostic.ISemanticSequencerDiagnosticProvider;
import org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic.Acceptor;
import org.eclipse.xtext.serializer.sequencer.AbstractSemanticSequencer;
import org.eclipse.xtext.serializer.sequencer.GenericSequencer;
import org.eclipse.xtext.serializer.sequencer.ISemanticNodeProvider.INodesForEObjectProvider;
import org.eclipse.xtext.serializer.sequencer.ISemanticSequencer;
import org.eclipse.xtext.serializer.sequencer.ITransientValueService;
import org.eclipse.xtext.serializer.sequencer.ITransientValueService.ValueTransient;

@SuppressWarnings("restriction")
public class AbstractKM3SemanticSequencer extends AbstractSemanticSequencer {

	@Inject
	protected KM3GrammarAccess grammarAccess;
	
	@Inject
	protected ISemanticSequencerDiagnosticProvider diagnosticProvider;
	
	@Inject
	protected ITransientValueService transientValues;
	
	@Inject
	@GenericSequencer
	protected Provider<ISemanticSequencer> genericSequencerProvider;
	
	protected ISemanticSequencer genericSequencer;
	
	
	@Override
	public void init(ISemanticSequencer sequencer, ISemanticSequenceAcceptor sequenceAcceptor, Acceptor errorAcceptor) {
		super.init(sequencer, sequenceAcceptor, errorAcceptor);
		this.genericSequencer = genericSequencerProvider.get();
		this.genericSequencer.init(sequencer, sequenceAcceptor, errorAcceptor);
	}
	
	public void createSequence(EObject context, EObject semanticObject) {
		if(semanticObject.eClass().getEPackage() == KM3Package.eINSTANCE) switch(semanticObject.eClass().getClassifierID()) {
			case KM3Package.ATTRIBUTE:
				if(context == grammarAccess.getAttributeRule() ||
				   context == grammarAccess.getFeatureRule()) {
					sequence_Attribute(context, (Attribute) semanticObject); 
					return; 
				}
				else break;
			case KM3Package.DATATYPE:
				if(context == grammarAccess.getClassifierRule() ||
				   context == grammarAccess.getDatatypeRule()) {
					sequence_Datatype(context, (Datatype) semanticObject); 
					return; 
				}
				else break;
			case KM3Package.ENUMERATION:
				if(context == grammarAccess.getClassifierRule() ||
				   context == grammarAccess.getEnumerationRule()) {
					sequence_Enumeration(context, (Enumeration) semanticObject); 
					return; 
				}
				else break;
			case KM3Package.KM3_CLASS:
				if(context == grammarAccess.getClassifierRule() ||
				   context == grammarAccess.getKM3ClassRule()) {
					sequence_KM3Class(context, (KM3Class) semanticObject); 
					return; 
				}
				else break;
			case KM3Package.LITERAL:
				if(context == grammarAccess.getLiteralRule()) {
					sequence_Literal(context, (Literal) semanticObject); 
					return; 
				}
				else break;
			case KM3Package.METAMODEL:
				if(context == grammarAccess.getMetamodelRule()) {
					sequence_Metamodel(context, (Metamodel) semanticObject); 
					return; 
				}
				else break;
			case KM3Package.MULTIPLICITY:
				if(context == grammarAccess.getMultiplicityRule()) {
					sequence_Multiplicity(context, (Multiplicity) semanticObject); 
					return; 
				}
				else break;
			case KM3Package.PACKAGE:
				if(context == grammarAccess.getPackageRule()) {
					sequence_Package(context, (org.dslintegration.kM3.Package) semanticObject); 
					return; 
				}
				else break;
			case KM3Package.REFERENCE:
				if(context == grammarAccess.getFeatureRule() ||
				   context == grammarAccess.getReferenceRule()) {
					sequence_Reference(context, (Reference) semanticObject); 
					return; 
				}
				else break;
			case KM3Package.TYPE_REF:
				if(context == grammarAccess.getTypeRefRule()) {
					sequence_TypeRef(context, (TypeRef) semanticObject); 
					return; 
				}
				else break;
			}
		if (errorAcceptor != null) errorAcceptor.accept(diagnosticProvider.createInvalidContextOrTypeDiagnostic(semanticObject, context));
	}
	
	/**
	 * Constraint:
	 *     (name=ID multiplicity=Multiplicity? typeRef+=TypeRef)
	 *
	 * Features:
	 *    name[1, 1]
	 *    multiplicity[0, 1]
	 *    typeRef[1, 1]
	 */
	protected void sequence_Attribute(EObject context, Attribute semanticObject) {
		genericSequencer.createSequence(context, semanticObject);
	}
	
	
	/**
	 * Constraint:
	 *     (datatype='datatype' name=ID)
	 *
	 * Features:
	 *    name[1, 1]
	 *    datatype[1, 1]
	 */
	protected void sequence_Datatype(EObject context, Datatype semanticObject) {
		if(errorAcceptor != null) {
			if(transientValues.isValueTransient(semanticObject, KM3Package.Literals.CLASSIFIER__NAME) == ValueTransient.YES)
				errorAcceptor.accept(diagnosticProvider.createFeatureValueMissing(semanticObject, KM3Package.Literals.CLASSIFIER__NAME));
			if(transientValues.isValueTransient(semanticObject, KM3Package.Literals.DATATYPE__DATATYPE) == ValueTransient.YES)
				errorAcceptor.accept(diagnosticProvider.createFeatureValueMissing(semanticObject, KM3Package.Literals.DATATYPE__DATATYPE));
		}
		INodesForEObjectProvider nodes = createNodeProvider(semanticObject);
		SequenceFeeder feeder = createSequencerFeeder(semanticObject, nodes);
		feeder.accept(grammarAccess.getDatatypeAccess().getDatatypeDatatypeKeyword_0_0(), semanticObject.getDatatype());
		feeder.accept(grammarAccess.getDatatypeAccess().getNameIDTerminalRuleCall_1_0(), semanticObject.getName());
		feeder.finish();
	}
	
	
	/**
	 * Constraint:
	 *     (enumeration='enumeration' name=ID literals+=Literal+)
	 *
	 * Features:
	 *    name[1, 1]
	 *    enumeration[1, 1]
	 *    literals[1, *]
	 */
	protected void sequence_Enumeration(EObject context, Enumeration semanticObject) {
		genericSequencer.createSequence(context, semanticObject);
	}
	
	
	/**
	 * Constraint:
	 *     (abstract?='abstract'? name=ID superType=[KM3Class|ID]? features+=Feature*)
	 *
	 * Features:
	 *    name[1, 1]
	 *    abstract[0, 1]
	 *    superType[0, 1]
	 *    features[0, *]
	 */
	protected void sequence_KM3Class(EObject context, KM3Class semanticObject) {
		genericSequencer.createSequence(context, semanticObject);
	}
	
	
	/**
	 * Constraint:
	 *     name=ID
	 *
	 * Features:
	 *    name[1, 1]
	 */
	protected void sequence_Literal(EObject context, Literal semanticObject) {
		if(errorAcceptor != null) {
			if(transientValues.isValueTransient(semanticObject, KM3Package.Literals.LITERAL__NAME) == ValueTransient.YES)
				errorAcceptor.accept(diagnosticProvider.createFeatureValueMissing(semanticObject, KM3Package.Literals.LITERAL__NAME));
		}
		INodesForEObjectProvider nodes = createNodeProvider(semanticObject);
		SequenceFeeder feeder = createSequencerFeeder(semanticObject, nodes);
		feeder.accept(grammarAccess.getLiteralAccess().getNameIDTerminalRuleCall_1_0(), semanticObject.getName());
		feeder.finish();
	}
	
	
	/**
	 * Constraint:
	 *     packages+=Package*
	 *
	 * Features:
	 *    packages[0, *]
	 */
	protected void sequence_Metamodel(EObject context, Metamodel semanticObject) {
		genericSequencer.createSequence(context, semanticObject);
	}
	
	
	/**
	 * Constraint:
	 *     (((lowerBound=INT upperBound=INT?) | unbounded?='*') ordered?='ordered'?)
	 *
	 * Features:
	 *    lowerBound[0, 1]
	 *         MANDATORY_IF_SET upperBound
	 *         EXCLUDE_IF_SET unbounded
	 *    upperBound[0, 1]
	 *         EXCLUDE_IF_UNSET lowerBound
	 *         EXCLUDE_IF_SET unbounded
	 *    unbounded[0, 1]
	 *         EXCLUDE_IF_SET lowerBound
	 *         EXCLUDE_IF_SET upperBound
	 *    ordered[0, 1]
	 */
	protected void sequence_Multiplicity(EObject context, Multiplicity semanticObject) {
		genericSequencer.createSequence(context, semanticObject);
	}
	
	
	/**
	 * Constraint:
	 *     (name=ID classifiers+=Classifier*)
	 *
	 * Features:
	 *    name[1, 1]
	 *    classifiers[0, *]
	 */
	protected void sequence_Package(EObject context, org.dslintegration.kM3.Package semanticObject) {
		genericSequencer.createSequence(context, semanticObject);
	}
	
	
	/**
	 * Constraint:
	 *     (name=ID multiplicity=Multiplicity? container?='container'? typeRef+=TypeRef opposite+=[Reference|ID]?)
	 *
	 * Features:
	 *    name[1, 1]
	 *    multiplicity[0, 1]
	 *    typeRef[1, 1]
	 *    container[0, 1]
	 *    opposite[0, 1]
	 */
	protected void sequence_Reference(EObject context, Reference semanticObject) {
		genericSequencer.createSequence(context, semanticObject);
	}
	
	
	/**
	 * Constraint:
	 *     type+=[Classifier|ID]
	 *
	 * Features:
	 *    type[1, 1]
	 */
	protected void sequence_TypeRef(EObject context, TypeRef semanticObject) {
		genericSequencer.createSequence(context, semanticObject);
	}
}
